package clearsyntax.collection;

import static java.util.Collections.EMPTY_SET;

import java.io.Serializable;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;

import clearsyntax.types.Tuple2;

// TODO This class needs a good name.
public final class Util {

	public static final EmptyIterator EMPTY_ITERATOR = new EmptyIterator();
	public static final EmptySortedSet EMPTY_SORTED_SET = new EmptySortedSet();
	public static final EmptySortedMap EMPTY_SORTED_MAP = new EmptySortedMap();

	@SuppressWarnings("unchecked")
	public static <T> Iterator<T> emptyIterator() {
		return (Iterator<T>) EMPTY_ITERATOR;
	}

	@SuppressWarnings("unchecked")
	public static <T> SortedSet<T> emptySortedSet() {
		return (SortedSet<T>) EMPTY_SORTED_SET;
	}

	@SuppressWarnings("unchecked")
	public static <K, V> SortedMap<K, V> emptySortedMap() {
		return (SortedMap<K, V>) EMPTY_SORTED_MAP;
	}

	public static <T> Iterator<T> unmodifiableIterator(Iterator<T> iterator) {
		return new UnmodifiableIterator<T>(iterator);
	}

	public static <T, C extends Collection<? super T>> C addAll(C collection, T... elems) {
		for (T elem : elems) {
			collection.add(elem);
		}
		return collection;
	}

	public static <K, V, M extends Map<? super K, ? super V>> M putAll(M map, Tuple2<? extends K, ? extends V>... entries) {
		for (Tuple2<? extends K, ? extends V> entry : entries) {
			map.put(entry._1, entry._2);
		}
		return map;
	}


	private static final class EmptySortedSet extends AbstractSet<Object> implements
			SortedSet<Object>, Serializable {

		private static final long serialVersionUID = 7354865225565805960L;

		@Override
		public Iterator<Object> iterator() {
			return EMPTY_ITERATOR;
		}

		@Override
		public int size() {
			return 0;
		}

		@Override
		public boolean contains(Object obj) {
			return false;
		}

		@Override
		public Comparator<? super Object> comparator() {
			return null;
		}

		@Override
		public Object first() {
			throw new NoSuchElementException();
		}

		@Override
		public Object last() {
			throw new NoSuchElementException();
		}

		@Override
		public SortedSet<Object> subSet(Object fromElement, Object toElement) {
			return EMPTY_SORTED_SET;
		}

		@Override
		public SortedSet<Object> headSet(Object toElement) {
			return EMPTY_SORTED_SET;
		}

		@Override
		public SortedSet<Object> tailSet(Object fromElement) {
			return EMPTY_SORTED_SET;
		}

		@Override
		public boolean equals(Object o) {
			return (o instanceof SortedSet) && ((SortedSet<?>) o).size() == 0;
		}

		@Override
		public int hashCode() {
			return 0;
		}

	}

	private static final class EmptySortedMap extends AbstractMap<Object, Object>
			implements SortedMap<Object, Object>, Serializable {

		private static final long serialVersionUID = -415143478231289337L;

		@Override
		public int size() {
			return 0;
		}

		@Override
		public boolean isEmpty() {
			return true;
		}

		@Override
		public boolean containsKey(Object key) {
			return false;
		}

		@Override
		public boolean containsValue(Object value) {
			return false;
		}

		@Override
		public Object get(Object key) {
			return null;
		}

		@Override
		@SuppressWarnings("unchecked")
		public Set<Object> keySet() {
			return EMPTY_SET;
		}

		@Override
		@SuppressWarnings("unchecked")
		public Collection<Object> values() {
			return EMPTY_SET;
		}

		@Override
		@SuppressWarnings("unchecked")
		public Set<Entry<Object, Object>> entrySet() {
			return EMPTY_SET;
		}

		@Override
		public Comparator<? super Object> comparator() {
			return null;
		}

		@Override
		public Object firstKey() {
			throw new NoSuchElementException();
		}

		@Override
		public Object lastKey() {
			throw new NoSuchElementException();
		}

		@Override
		public SortedMap<Object, Object> subMap(Object fromKey, Object toKey) {
			return EMPTY_SORTED_MAP;
		}

		@Override
		public SortedMap<Object, Object> headMap(Object toKey) {
			return EMPTY_SORTED_MAP;
		}

		@Override
		public SortedMap<Object, Object> tailMap(Object fromKey) {
			return EMPTY_SORTED_MAP;
		}

		@Override
		public boolean equals(Object o) {
			return (o instanceof SortedMap)
					&& ((SortedMap<?, ?>) o).size() == 0;
		}

		@Override
		public int hashCode() {
			return 0;
		}

	}

	private static final class EmptyIterator implements Iterator<Object> {

		public boolean hasNext() {
			return false;
		}

		public Object next() {
			throw new NoSuchElementException();
		}

		public void remove() {
			throw new UnsupportedOperationException();
		}

	}

	private static final class UnmodifiableIterator<T> implements Iterator<T> {

		private final Iterator<T> iterator;

		private UnmodifiableIterator(Iterator<T> iterator) {
			if (iterator == null) {
				throw new NullPointerException();
			}
			this.iterator = iterator;
		}

		public boolean hasNext() {
			return iterator.hasNext();
		}

		public T next() {
			return iterator.next();
		}

		public void remove() {
			throw new UnsupportedOperationException();
		}

	}

}
